//
//  uiNodeManager.cpp
//  smu_test1
//
//  Created by jiayi on 16/9/25.
//
//

#include "uiCommon.hpp"
#include "smuNode.h"
#include "uiNodeManager.h"
#include "smuNodeReader.h"
#include "smuGraph.h"

uiNodeManager::~uiNodeManager()
{
    _root = nullptr;
}

int uiNodeManager::initializeData()
{
    // initialize graph
    _graph = new smuGraph();
    _graph->setUpdateFinishedFunction( std::bind( &uiNodeManager::updateCallback, this, std::placeholders::_1, std::placeholders::_2 ) );
    
    // add fake a node as the start one
    _root = _addNode( "", true );
    
    // read config
    smuNodeReader reader;
    int ret = reader.loadResourceFile( resource_file );
    if( ret == smuError::ok ){
        smuNodeReader::smuReaderData& data = reader.getReaderData();
        smuNodeReader::smuReaderDataIter iter = data.begin();
        for( ; iter != data.end(); ++ iter ){
            processString( *iter, false );
        }
    }
    
    endAddNodes();

    return ret;
}

void uiNodeManager::endAddNodes()
{
    // add empty node to root
    for( uiNodeDatasIter iter = _emptyFromDatas.begin(); iter != _emptyFromDatas.end(); ++ iter ){
        _addLink( _root, iter->second, false );
    }
    _emptyFromDatas.clear();
}

void uiNodeManager::destroyData()
{
    saveData();
    smuDelete( _graph );
    _datas.clear();
    _newDatas.clear();
    _emptyFromDatas.clear();
}

void uiNodeManager::saveData()
{
    smuNodeReader reader;
    smuNodeReader::smuReaderData& data = reader.getReaderData();
    _graph->save( _root->getNodeData(), data );
    reader.saveResourceFile( resource_file );
}

void uiNodeManager::processString( string &line, bool fake )
{
    if( line.empty() ){
        return;
    }
    
    trim( line );
    // if no spaces, return
    string::size_type spacePosition = line.find(' ');
    if( spacePosition == string::npos ){
        // single word, add directly
        std::string nodeName = line;
        uiNode* node = _addNode( trim( nodeName ), fake );
        _graph->updateBFS( node->getNodeData(), EUpdate::Initialize );
        return;
    }
    
    // get names of resource and it's rely
    std::string nodeName = line.substr( 0, spacePosition );
    std::string relyName = line.substr( spacePosition );
    
    uiNode* node = _addNode( nodeName, fake );
    uiNode* rely = _addNode( relyName, fake );
    
    _addLink( node, rely );
}

void uiNodeManager::_addLink( uiNode* n1, uiNode* n2, bool eraseEmpty /*= true*/  )
{
    if( eraseEmpty ){
        _emptyFromDatas.erase( n2->getNodeData()->name );
    }
    
    if( !_graph->addLink( n1->getNodeData(), n2->getNodeData() ) ){
        return;
    }
    
    n2->addFromAndRely( n1 );
    _graph->updateBFS( n2->getNodeData(), EUpdate::Initialize );
    
}

uiNode* uiNodeManager::_addNode( std::string name, bool fake )
{
    trim( name );
    uiNodeDatasConstIter nodeDataIter = _datas.find( name );
    
    if( nodeDataIter != _datas.end() ){
        return nodeDataIter->second;
    }else{
        // create one
        smuNode* data = new smuNode();
        data->name = name;
        uiNode* node = uiNode::create();
        node->setNodeData( data );
        
        _datas.insert( name, node );
        if( !fake ){
            if( _emptyFromDatas.find( name ) == _emptyFromDatas.end() ){
                _emptyFromDatas.insert( name, node );
            }
        }
        node->setFake( fake );
        return node;
    }
}

void uiNodeManager::deleteOrRestoreNode(smuNode *node, bool del)
{
    node->setDeleted( del );
    _graph->updateBFS( node, EUpdate::Status );
}


void uiNodeManager::updateCallback( smuNode* node, int param )
{
    if( !node ){
        return;
    }
    uiNode* uinode = ( _datas.find( node->name ) )->second;
    if( !uinode ){
        return;
    }
    
    uiUpdateNode* update = uiFactory< uiUpdateNode >::getInstance().getObject();    
    update->updateType = param;
    update->node = uinode;    
    _newDatas.pushBack( update );
}
